/*
* Copyright © Shanghai Awinic Technology Co., Ltd. 2020-2020. All rights reserved.
* Description: GPIO driver related library function files.
* Date： 20201126
* Awinic_Version： aw_soc_driver_v1.0.0
*/
#include "compile_option.h"
#ifdef AW_86802

#include "aw8680x_global.h"

/**
  * @brief  GPIO interrupt number configuration function
  * @param  gpio_irq_pri_e is used to set interrupt priority
  * @retval AW library status
  */
static void gpio_irq_config(IRQ_PRI_E gpio_irq_pri_e)
{
	NVIC_EnableIRQ(IRQ_GPIO); // Enable GPIO Interrupt
	NVIC_SetPriority(IRQ_GPIO, gpio_irq_pri_e); // Set Interrupt Priority
}

/**
  * @brief  GPIO Interrupt type configuration function
  * @param  GPIO pointer to a GPIO_HANDLE_TYPE_S structure that contains
  *         the configuration information for the specified GPIO.
  * @retval RET_STATUS_E status
  */
static RET_STATUS_E gpio_set_exti_type(GPIO_HANDLE_TYPE_S *p_gpio_lib)
{
	/* Check the GPIO handle allocation. */
	if (p_gpio_lib == AW_NULL) {
		return RET_ERROR;
	}

	if (p_gpio_lib->init_s.ext_type == HIGH_LEVEL) {
		/* Configured as high level trigger mode */
		GPIO->INT_TYPE_LVL &= ~p_gpio_lib->init_s.gpio_pin;
		GPIO->INT_POLARITY |= p_gpio_lib->init_s.gpio_pin;
	} else if (p_gpio_lib->init_s.ext_type == LOW_LEVEL) {
		/* Configured as low level trigger mode */
		GPIO->INT_TYPE_LVL &= ~p_gpio_lib->init_s.gpio_pin;
		GPIO->INT_POLARITY &= ~p_gpio_lib->init_s.gpio_pin;
	} else if (p_gpio_lib->init_s.ext_type == RISING_EDGE) {
		/* Configured as rising edge trigger mode */
		GPIO->INT_TYPE_LVL |= p_gpio_lib->init_s.gpio_pin;
		GPIO->INT_POLARITY |= p_gpio_lib->init_s.gpio_pin;
	} else if (p_gpio_lib->init_s.ext_type == FALLING_EDGE) {
		/* Configured as fallsing edge trigger mode */
		GPIO->INT_TYPE_LVL |= p_gpio_lib->init_s.gpio_pin;
		GPIO->INT_POLARITY &= ~p_gpio_lib->init_s.gpio_pin;
	}

	return RET_OK;
}

/**
  * @brief  GPIO gpio mode function
  * @param  gpio_mode, gpio_pin
  * @retval None
  */
void gpio_set_mode(GPIO_MODE_E gpio_mode, AW_U32 gpio_pin)
{
	if (gpio_mode == GPIO_INPUT) {
	/* Set this IO as input mode */
		GPIO->SWPOT_DDR &= ~gpio_pin;
		protect_unlock();
		SYS->PA_IN_EN |= gpio_pin; // GPIOA input function enable.
		SYS->PA_OD_EN |= gpio_pin; // OD
		protect_lock();
	} else if (gpio_mode == GPIO_OD_OUTPUT) {
	/* Set this IO as OD output mode */
		GPIO->SWPOT_DDR |= gpio_pin;
		protect_unlock();
		SYS->PA_IN_EN |= GPIO_OD_IN_FLAG; // OD_OUT and OD_IN
		SYS->PA_OD_EN |= gpio_pin; // OD
		protect_lock();
	} else if (gpio_mode == GPIO_PA_OUTPUT) {
		/* Set this IO as Push-pull output mode */
		GPIO->SWPOT_DDR |= gpio_pin;
		protect_unlock();
		SYS->PA_IN_EN &= ~(gpio_pin & GPIO_PA_OUT_FLAG); // OUTPUT
		SYS->PA_OD_EN &= ~(gpio_pin & GPIO_PA_OUT_FLAG); // Push_pull
		protect_lock();
	}
}

/**
  * @brief  GPIO initialization function
  * @param  GPIO pointer to a UART_HANDLE_TYPE_S structure that contains
  *         the configuration information for the specified GPIO.
  * @retval AW library status
  */
RET_STATUS_E gpio_init(GPIO_HANDLE_TYPE_S *p_gpio_lib)
{
	/* Check the GPIO handle allocation. */
	if (p_gpio_lib == AW_NULL) {
		return RET_ERROR;
	}

	/* Check the parameters */
	assert_param(GPIO_CHECK_MODE(p_gpio_lib.init_s.mode));

	gpio_clk_init(); // Enable the GPIO peripheral clock.
	gpio_pmux_init(p_gpio_lib->init_s.gpio_pin_mux); // Config gpio pin mux

	/* Config gpio mode */
	if (p_gpio_lib->init_s.mode == GPIO_INPUT) {
		/* Set this IO as input mode */
		GPIO->SWPOT_DDR &= ~p_gpio_lib->init_s.gpio_pin;
		protect_unlock();
		SYS->PA_IN_EN |= p_gpio_lib->init_s.gpio_pin; // GPIOA input function enable.
		SYS->PA_OD_EN |= p_gpio_lib->init_s.gpio_pin; // OD
		protect_lock();
	} else if (p_gpio_lib->init_s.mode == GPIO_OD_OUTPUT) {
		/* Set this IO as OD output mode */
		GPIO->SWPOT_DDR |= p_gpio_lib->init_s.gpio_pin;
		gpio_od_config_en(p_gpio_lib->init_s.gpio_pin);
	} else if (p_gpio_lib->init_s.mode == GPIO_PA_OUTPUT) {
		/* Set this IO as Push-pull output mode */
		GPIO->SWPOT_DDR |= p_gpio_lib->init_s.gpio_pin;
		gpio_pa_config_en(p_gpio_lib->init_s.gpio_pin);
	} else if (p_gpio_lib->init_s.mode == GPIO_EXTINT) {
		/* Set GPIO as external interrupt mode */
		gpio_irq_config(p_gpio_lib->gpio_irq_pri_e);
		GPIO->SWPOT_DDR &= ~p_gpio_lib->init_s.gpio_pin; // Config gpio input
		GPIO->INT_MASK &= ~p_gpio_lib->init_s.gpio_pin; // Config gpio mask
		gpio_set_exti_type(p_gpio_lib); // Set gpio external interrupt type
		GPIO->INT_EN |= p_gpio_lib->init_s.gpio_pin; // Enable gpio interruption
	}

	if (p_gpio_lib->init_s.gpio_speed == GPIO_SPEED_FAST) {
		gpio_speed_fast(p_gpio_lib->init_s.gpio_pin);
	} else if (p_gpio_lib->init_s.gpio_speed == GPIO_SPEED_SLOW) {
		gpio_speed_slow(~p_gpio_lib->init_s.gpio_pin);
	}

	return RET_OK;
}

/**
  * @brief  GPIO input state function
  * @param  gpio_pin
  * @retval GPIO_PIN_STATE_E status
  */
GPIO_PIN_STATE_E gpio_get_state(AW_U32 gpio_pin)
{
	AW_U32 gpio_current_state = AW_NUM_NULL;
	GPIO_PIN_STATE_E gpio_state_e = GPIO_LOW;

	/* Get Current IO status */
	gpio_current_state = GPIO->EXT_POT & gpio_pin;

	if (gpio_current_state != AW_NUM_NULL) {
		gpio_state_e = GPIO_HIGH;
	} else {
		gpio_state_e = GPIO_LOW;
	}

	return gpio_state_e;
}

/**
  * @brief  GPIO external interruption of service function
  * @param  None
  * @retval None
  */
__weak void gpio_irq(void)
{
	AW_U32 gpio_pin = 0;

	/* NOTE : This function Should not be modified, when the gpio_irq() is needed,
			the gpio_irq() could be implemented in the user file.
	*/

	GPIO_CLEAN_MASK(gpio_pin);
}
#endif
